Warum mu� die Bitmap eigentlich 576 Pixel hoch sein? Zuerst einmal mu� man sagen, da� die Bitmap generell h�her sein mu� als der sichtbare Bereich, weil wir "neu hereinkommende" Levelbereiche blockweise blitten und das in einem Bereich machen m�ssen, den man nicht sieht - sonst sieht das f�r den User gar nicht sch�n oder professionell aus. Der sichtbare Bereich betr�gt 256 Pixel in der H�he, d. h. 16 Bl�cke (SICHTBARE H�HE : BLOCKH�HE = 256 : 16 = 16). Es sind aber nicht immer nur 16 Bl�cke vertikal sichtbar, meistens sind es 17, n�mlich immer dann, wenn die Levelposition (d. h. die vertikale Position des Levelausschnittes in Pixel) nicht durch 16 (BLOCKH�HE) teilbar ist.
256 + 32 ist aber nur 288? War da nicht die Rede von 576 Pixeln? Nun, auf 576 Pixel kommen wir, wenn wir 288 mit 2 multiplizieren. Der wesentliche Trick von diesem Scroll-Algorithmus besteht n�mlich darin, da� unsere Bitmap doppelt so hoch ist, wie sie eigentlich sein m��te. Die untere H�lfte ist stets eine exakte Kopie der oberen H�lfte. Deshalb wird beim Scrollen jeder zu blittende Block einmal in der oberen und einmal in der unteren H�lfte geblittet. So ganz richtig mit der exakten Kopie ist das aber nur solange keine BOBs geblittet werden. Die m�ssen n�mlich zum Gl�ck nur einmal geblittet werden. Das aber nur nebenbei gesagt. Zu Beginn f�llen wir die beiden Bitmaph�lften mit dem anfangs sichtbaren Levelbereich:
Das rote Rechteck stellt den am Anfang aktuellen Bereich dar, der mit dem Copper dargestellt wird, wobei die ersten und letzten 16 Pixel ausgeblendet sind. Der User sieht also nur den vom gelben Rechteck eingegrenzten Bereich. Wenn wir nach unten scrollen, dann verschiebt sich auch der aktuelle Bereich nach unten. Wenn wir nach oben scrollen, dann verschiebt er sich nach oben. Den sichtbaren Bereich zu verschieben reicht nat�rlich nicht aus. Wir m�ssen auch die neu hereinkommenden Bl�cke in die Bitmap blitten. Gehen wir mal davon aus, da� wir nach unten wollen. Am Anfang befinden sich in den beiden Bitmaph�lften die Blockreihen 0 bis 17, also die ersten 18 Reihen des Levels. Nach sp�testens 16 Pixeln (= H�he einer Reihe) Nach-Unten-Scrollen m�ssen sich die Blockreihen 1 bis 18 in beiden Bitmaph�lften befinden. Da wir 16 Pixel lang Zeit dazu haben blitten wir die neue (18) Blockreihe nicht auf einmal, sondern schrittweise. 16 Pixel Zeit hei�t, da� wir sie in 16 Schritten blitten. Eine Blockreihe besteht aus 20 (BITMAPBREITE : BLOCKBREITE = 320 : 16 = 20) Bl�cken. Das w�rde bedeuten, da� wir pro Schritt 1,25 (20 : 16 = 1,25) Bl�cke blitten m��ten. Wir blitten aber nur ganze Bl�cke, also l�sen wir das so, da� wir mal einen, mal zwei Bl�cke blitten. Bei wievielen der 16 Schritte wir 2 Bl�cke blitten m�ssen, um beim letzten Schritt die Reihe (20 Bl�cke) komplett zu haben, berechnen wir so:
2 * x + (ANZAHLSCHRITTE - x) * 1 = BL�CKEPROREIHE2x + (16 - x) * 1 = 20
2x + 16 - x = 20
x = 20 - 16
x = 4
Das bedeutet also in unserm Fall, das wir bei 4 der insgesamt 16 Schritten zwei Bl�cke blitten und bei den restlichen 12 Schritten nur einen Block. In den Demo Quelltexten zu diesem Algorithmus wird bei den letzten 4 Schritten doppelt geblittet, man kann das aber nat�rlich auch bei den ersten 4 Schritten machen.
Welchen Schritt = welchen Block bzw. welche 2 Bl�cke wir in einer bestimmten Situation (= LevelPosition) blitten m�ssen, berechnen wir, indem wir die LevelPositionY durch 16 (BLOCKH�HE) dividieren und uns den Rest anschauen. Der n�mlich bestimmt den Schritt. Den Rest berechnen wir in C entweder mit dem Modulo Operator (%), oder, weil 16 eine 2er Potenz ist mit einem bin�ren UND:
1) LevelPositionY % BLOCKH�HE2) LevelPositionY & (BLOCKH�HE -1)
Dabei erh�lt man Werte zwischen 0 und BLOCKH�HE - 1, in unserem Falle (d. h. Blockh�he 16 Pixel) also zwischen 0 und 15. Der sich in der Reihe ganz links befindende Block ist Block 0, der ganz rechts Block 19. Wir gingen davon aus, nach unten zu scrollen, wollen also von LevelPositionY 0 zu LevelPositionY 1. Da der errechnete Schritt f�r Levelposition 1 gleich 1 ist, wir aber zuerst den Block ganz links (= Block 0) blitten m�ssen bzw. wollen, erh�hen wir die Variable f�r LevelPositionY (in den Quelltexten mapposy genannt) erst am Ende der ScrollRunter() Funktion. So erhalten wir f�r das Scrolling von Levelposition 0 nach Levelposition 1 den Schrittwert 0, f�r das Scrolling von Levelposition 1 nach Levelposition 2 den Schrittwert 1 usw. Bei den Schritten 0 .. 11 blitten wir den Block SCHRITT der "Nachf�llreihe". Bei den Schritten 12 .. 15 (die letzten 4) blitten wir den Block 12 + (SCHRITT - 12) * 2 und den Block 12 + (SCHRITT - 12) * 2 + 1. So wird die Reihe nach und nach mit dem neuen Levelbereich gef�llt.
Eine Frage ist nat�rlich noch offen. An welcher Y-Position befindet sich die Nachf�llreihe in der Bitmap - wo m�ssen die neuen Bl�cke geblittet werden? Antwort: An der Stelle, wo sich die "hinauswandernde" Blockreihe befindet. Im obigen Beispiel w�re das die Reihe 0. Da w�hrend des Scrollens jeder Block zweimal geblittet wird, also einmal in der oberen und einmal in der unteren der beiden Bitmaph�lften wandert der aktuell sichtbare Bereich beim Nach-Unten-Scrollen langsam in Richtung der Nachf�llreihe der unteren Bitmaph�lfte. Sie wird gerade rechtzeitig fertig gef�llt sein, also noch bevor der User sie zu Gesicht bekommt. Denn sobald das geschieht ist die Nachf�llreihe bereits vertikal einen Block weiterger�ckt. In den Quelltexten enth�lt die Variable videoposy die Position des aktuellen Bitmapbereiches (rotes Rechteck). Daraus errechnen wir die Position in der Bitmap, an der sich die Nachf�llreihe befindet, d. h. wo wir die Bl�cke blitten m�ssen. Dazu gibt es wieder eine langsame (1) und eine schnelle (2) Methode, wobei letztere wieder nur dann funktioniert wenn BLOCKH�HE ein 2er Potenz ist:
1) y = videoposy - (videoposy % BLOCKH�HE)Diese Formel errechnet die Position in der oberen Bitmaph�lfte. F�r den Blit in die untere Bitmaph�lfte addieren wir einfach HALBEBITMAPH�HE, d. h. 288. In den Demo Quelltexten wird dieser Wert noch mit ANZPLANES multipliziert, weil die Blockblit-Routine die Y-Koordinate in Planelines (1 Pixelzeile besteht aus ANZPLANES Planelines) erwartet.2) y = videoposy & ~(BLOCKH�HE - 1)
Das nach Oben-Scrollen geschieht analog, mit dem Unterschied, da� wir die LevelPositionY nicht am Ende der Scroll-Funktion �ndern, sondern am Anfang. Wir verwenden sozusagen Pre-Dekrement im Gegensatz zum Post-Inkrement beim Nach-Unten-Scrollen. Der Grund ist ganz einfach. Stellen wir uns vor, wir sind von LevelPosition 0 nach LevelPosition 1, also 1 Pixel nach unten, gescrollt. Das Ergebnis ist, da� Block 0 (ganz links) der Nachf�llspalte einen unten hereinkommenden Block, genauer gesagt Block (0,18), d. h. den 19. Block der Levelspalte ganz links, enth�lt - im folgenden Bild als ein gelbes Rechteck mit roter Umrandung dargestellt:
Wir befinden uns also an Levelposition 1 und wollen wieder zur�ck nach Levelposition 0, d. h. der gelb-rote Block mu� weg und mit Block (0,0) ersetzt werden. Aus Levelposition 1 errechnet sich der Schritt 1, was falsch ist, weil das bedeuten w�rde den Block (1,0) rechts neben dem gelb-roten Block zu blitten. Wenn wir die Levelposition aber am Anfang der ScrollRauf() Funktion �ndern, dann errechnet sich der Schritt aus Levelposition 0 und wir erhalten als Ergebnis 0 (0 % 16 = 0). Das hei�t dann f�r die Scroll-Funktion Block (0,0) �ber das gelb-rote Rechteck zu blitten - genau das was wir wollen :-)
Wie bereits gesagt, wird der "aktuelle" und sichtbare Bitmapbereich (rotes Rechteck im vorvorletztem Bild) beim Scrollen analog zur Scroll-Richtung verschoben. Was passiert aber, wenn wir so weit nach unten gescrollt haben, da� der Bereich Gefahr l�uft �ber die Bitmapgrenzen hinauszulaufen? Das passiert ja schon nach 288 Pixeln. Ganz einfach. Wenn wir so weit nach unten gescrollt sind, dann setzen wir den aktuellen und somit automatisch auch den sichtbaren Bitmapbereich wieder an den Anfang der Bitmap (Position 0). Das geht deshalb, weil die obere und untere Bitmaph�lfte ja genau gleich ausschauen. Und wenn der Bereich droht, oben �ber die Bitmapgrenze hinauszuscrollen, dann setzen wir ihn einfach an das untere Maximum (Position 287). Ganz konkret hei�t das, da� sich die Position des "aktuellen" Bitmapbereichs durch folgende Formel errechnet:
videoposy = LevelPositionY % HALBEBITMAPH�HE, d. h.
videoposy = LevelPositionY % 288
Noch einige Bemerkungen zum Quelltext des Demoprogrammes. Wenn die Variable mapposy, die die Levelposition Y in Pixeln enth�lt, auf 0 steht, dann sieht der User den Levelbereich ab Position BLOCKH�HE (16), weil die ersten BLOCKH�HE (16) Pixel stets verdeckt sind. Der User sieht also den Bereich:
(0,mapposy + BLOCKHEIGHT) - (SCREENWIDTH - 1,mapposy + BLOCKHEIGHT + SCREENHEIGHT - 1)
Das hei�t, da� die erste Blockreihe der Leveldatei nie sichtbar ist. Will man in die Bitmap etwas hineinblitten, z. B. Blitter Objekte (BOBs), dann mu� man das im aktuell sichtbaren Bitmapbereich machen. Dieser Bereich ist:
(0,videoposy + BLOCKHEIGHT) - (SCREENWIDTH - 1,videoposy + BLOCKHEIGHT + SCREENHEIGHT - 1)
Man darf die Start-Y Koordinate (videoposy + BLOCKHEIGHT) und die End-Y Koordinate (videoposy + BLOCKHEIGHT + SCREENHEIGHT - 1) auf ein Vielfaches von BLOCKHEIGHT auf- bzw. abrunden, soda� der Bereich, in den geblittet werden darf insgesamt SCREENHEIGHT + BLOCKHEIGHT Pixel hoch ist:
blitbereich_strty = (videoposy + BLOCKHEIGHT) & ~(BLOCKHEIGHT - 1)blitbereich_endey = blitbereich_strtx + SCREENHEIGHT + BLOCKHEIGHT - 1